package com.framework.modules.common.controller;

import java.util.HashMap;
import java.util.Map;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.framework.common.config.SystemConfigName;
import com.framework.common.utils.*;
import com.framework.config.DatabaseInitConfig;
import com.framework.modules.base.entity.*;
import com.framework.modules.base.service.*;
import com.framework.modules.common.channel.other.OtherPayConfig;
import com.framework.modules.common.service.BaseService;
import com.framework.modules.live.entity.*;
import com.framework.modules.live.service.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.bind.annotation.*;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import javax.servlet.http.HttpServletRequest;

/**
 * 登录接口
 */
@RestController
@RequestMapping("/notify")
@DependsOn("databaseInitConfig")
@Api(tags = "外部通知")
public class NotifyController {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private OtherPayConfig otherPayConfig;

    @Autowired
    private UserOrderService userOrderService;

    @Autowired
    private LiveLogService liveLogService;

    @Autowired
    private LiveRoomService liveRoomService;

    @Autowired
    private LiveSnapshotService liveSnapshotService;

    @Autowired
    private LiveVideoService liveVideoService;

    @Autowired
    private LivePornLogService livePornLogService;

    @Autowired
    private BaseService baseService;

    @Autowired
    private LiveHistoryService liveHistoryService;

//    @RequestMapping("reload_system_environment")
//    @ApiOperation("重新载入数据库配置")
//    public R reloadSystemEnvironment() {
//        DatabaseInitConfig.reloadConfig();
//        return R.ok();
//    }

    @RequestMapping("zhibo")
    @ApiOperation("腾讯直播通知")
    public R zhibo(@RequestParam("action") String action, @RequestBody Map<String,String> params) {

        JSONObject obj = QuickHelper.getConfigJSONObject(SystemConfigName.ZHIBO_SDK_CONFIG);
        JSONObject activeConfig = obj.getJSONObject("templateConfig").getJSONObject(obj.getString("active"));

        String t = params.get("t").toString();
        String key = activeConfig.getString("CallbackKey");
        String hash = QuickHelper.md5(key + "" + t);
        String raw = QuickHelper.object2json(params);
        logger.info(String.format("==================== notify action : %s , hash = %s ====================", action, hash));
        logger.info(raw);
        if (!params.get("sign").toString().equals(hash)) {
            return R.error(-2, "腾讯云直播通知回调，签名错误");
        }

        /**
         * 直播开始和结束通知
         */
        if("streamBegin".equals(action) || "streamEnd".equals(action)) {

            LiveLogEntity entity = new LiveLogEntity();
            entity.setAction(action);
            entity.setAppid(params.get("appid").toString());
            entity.setApp(params.get("app").toString());
            entity.setAppname(params.get("appname").toString());
            entity.setStreamId(params.get("stream_id").toString());
            entity.setChannelId(params.get("channel_id").toString());
            entity.setEventType(params.get("event_type").toString());
            entity.setEventTime(params.get("event_time").toString());
            entity.setSequence(params.get("sequence").toString());
            entity.setNode(params.get("node").toString());
            entity.setUserIp(params.get("user_ip").toString());
            entity.setStreamParam(params.get("stream_param").toString());
            entity.setPushDuration(params.getOrDefault("push_duration", "0").toString());
            entity.setErrcode(params.get("errcode").toString());
            entity.setErrmsg(params.get("errmsg").toString());
            entity.setRaw(raw);
            entity.setAdddate(QuickHelper.getNowTimeStampSeconds());

            Integer uid = 0;

            try {
                uid = Integer.valueOf(params.get("stream_id"));
            } catch (Exception e) {
                logger.info(String.format("uid = %s , convert error : %s", uid, e.getMessage()));
            }

            /**
             * 推流开始回调
             */
            if ("streamBegin".equals(action)) {
                String roundId = BizSequenceUtils.getInstance().generateBizSeqNo("live_");
                LiveRoomEntity roomEntity = new LiveRoomEntity();
                roomEntity.setUid(uid);
                roomEntity.setLiveRoundId(roundId);
                roomEntity.setStartDate(QuickHelper.getNowTimeStampSeconds());
                roomEntity.setState(1);
                liveRoomService.updateById(roomEntity);
                logger.info(String.format("直播室 %s 直播开始", uid));
            }

            /**
             * 推流结束回调
             */
            if ("streamEnd".equals(action)) {

                /**
                 * 查询当前直播间状态
                 */
                LiveRoomEntity roomEntity = liveRoomService.selectById(uid);
                Integer timestamp = QuickHelper.getNowTimeStampSeconds();
                Integer state = 0;
                /**
                 * 如果腾讯返回禁止直播
                 */
                if(entity.getErrcode().equals("21")) {
                    state = -2;
                }
                /**
                 * 更新直播室的状态为停止直播状态
                 */
                Integer millionSeconds = Integer.valueOf(params.getOrDefault("push_duration", "0"));
                double seconds = (double) millionSeconds / 1000;
                seconds = Math.ceil(seconds);
                liveRoomService.updateStreamEndLiveRoom((int) seconds, timestamp,state, uid);
                logger.info(String.format("直播室 %s 直播结束，累计 %s 秒 , %s 毫秒", uid, seconds, millionSeconds));

                /**
                 * 插入一条直播历史记录
                 */

                LiveHistoryEntity liveHistoryEntity = new LiveHistoryEntity();
                liveHistoryEntity.setId(roomEntity.getLiveRoundId());
                liveHistoryEntity.setUid(uid);
                liveHistoryEntity.setStartDate(roomEntity.getStartDate());
                liveHistoryEntity.setEndDate(timestamp);
                liveHistoryEntity.setGiftCount(roomEntity.getGiftCount());
                liveHistoryEntity.setPopCount(roomEntity.getPopCount());
                liveHistoryEntity.setOnlineCount(roomEntity.getOnlineCount());
                liveHistoryEntity.setTotalSeconds(roomEntity.getTotalSeconds());
                liveHistoryEntity.setAdddate(timestamp);
                Boolean result = liveHistoryService.insert(liveHistoryEntity);

                logger.info(String.format("直播室 %s 直播结束，归档历史记录 => %s", uid, result));
            }

            Boolean b = liveLogService.insert(entity);

            return b ? R.ok(0, "通知完成，入库成功") : R.error(-1, "入库失败");
        }


        /**
         * 截图通知
         */
        if("snapshot".equals(action)){
            /*
            * {
                    "event_type": 200,
                    "stream_id": "stream_name",
                    "channel_id": "stream_name",
                    "create_time": 1545030273,
                    "file_size": 7520,
                    "width": 640,
                    "height": 352,
                    "pic_url": "/2018-12-17/stream_name-screenshot-19-06-59-640x352.jpg",
                    "pic_full_url": "http://testbucket-1234567890.cos.region.myqcloud.com/2018-12-17/stream_name-screenshot-19-06-59-640x352.jpg",
                    "sign": "ca3e25e5dc17a6f9909a9ae7281e300d",
                    "t": 1545030873
                }
            * */

            Integer uid = 0;

            try {
                uid = Integer.valueOf(params.get("stream_id"));
            } catch (Exception e) {
                logger.info(String.format("uid = %s , convert error : %s", uid, e.getMessage()));
            }

            //查询当前直播室
            LiveRoomEntity liveRoomEntity = liveRoomService.selectById(uid);

            LiveSnapshotEntity entity = new LiveSnapshotEntity();
            entity.setTitle(liveRoomEntity.getTitle());
            entity.setLiveRoundId(liveRoomEntity.getLiveRoundId());
            entity.setStreamId(params.get("stream_id").toString());
            entity.setChannelId(params.get("channel_id").toString());
            entity.setCreateTime(Integer.valueOf(params.get("create_time")));
            entity.setFileSize(Integer.valueOf(params.get("file_size").toString()));
            entity.setImgWidthHeight(String.format("%s,%s", params.get("width").toString(),params.get("height").toString()));
            entity.setPicUrl(params.get("pic_url").toString());
            entity.setPicFullUrl(params.get("pic_full_url").toString());
            entity.setRaw(raw);
            entity.setAdddate(QuickHelper.getNowTimeStampSeconds());



            Boolean  result = liveSnapshotService.insert(entity);
            String msg = String.format("直播通知 截图归档成功 : %s ", entity.getPicFullUrl());
            if(result){
                logger.info(msg);

                //更新直播室的当前截图
                LiveRoomEntity roomEntity = new LiveRoomEntity();
                roomEntity.setSnapshotImage(entity.getPicFullUrl());
                roomEntity.setUid(uid);
                liveRoomService.updateById(roomEntity);

                return  R.ok(msg);
            }
            else{
                msg = "直播通知 截图归档失败";
                logger.info(msg);
                return  R.ok(msg);
            }
        }

        /**
         * 录像通知
         */
        if("record".equals(action)){
            /*
            {
                "event_type": 100,
                "appid": 12345678,
                "stream_id": "stream_test",
                "channel_id": "stream_test",
                "file_id": "1234567890",
                "file_format": "hls",
                "start_time": 1545047010,
                "end_time": 1545049971,
                "duration": 2962,
                "file_size": 277941079,
                "stream_param": "stream_param=test",
                "video_url": "http://12345678.vod2.myqcloud.com/xxxx/yyyy/zzzz.m3u8",
                "sign": "ca3e25e5dc17a6f9909a9ae7281e300d",
                "t": 1545030873
            }
            * */

            Integer uid = 0;

            try {
                uid = Integer.valueOf(params.get("stream_id"));
            } catch (Exception e) {
                logger.info(String.format("uid = %s , convert error : %s", uid, e.getMessage()));
            }


            //查询当前直播室
            LiveRoomEntity liveRoomEntity = liveRoomService.selectById(uid);

            LiveVideoEntity entity = new LiveVideoEntity();
            entity.setTitle(liveRoomEntity.getTitle());
            entity.setLiveRoundId(liveRoomEntity.getLiveRoundId());
            entity.setStreamId(params.get("stream_id").toString());
            entity.setChannelId(params.get("channel_id").toString());
            entity.setAppid(params.get("appid").toString());

            entity.setFileId(params.get("file_id").toString());
            entity.setFileFormat(params.get("file_format").toString());
            entity.setFileSize(Integer.valueOf(params.get("file_size").toString()));

            entity.setDuration(Integer.valueOf(params.get("duration").toString()));
            entity.setStartTime(Integer.valueOf(params.get("start_time").toString()));
            entity.setEndTime(Integer.valueOf(params.get("end_time").toString()));

            entity.setStreamParam(params.get("stream_param").toString());
            entity.setVideoUrl(params.get("video_url").toString());
            entity.setRaw(raw);
            entity.setAdddate(QuickHelper.getNowTimeStampSeconds());


            Boolean  result = liveVideoService.insert(entity);
            String msg = String.format("直播通知 录像归档成功 : %s ", entity.getVideoUrl());
            if(result){
                logger.info(msg);
                return  R.ok(msg);
            }
            else{
                msg = "直播通知 录像归档失败";
                logger.info(msg);
                return  R.ok(msg);
            }
        }

        /**
         * 直播鉴黄通知
         */
        if("porn".equals(action)){
            /*
            id INT    COMMENT '编号' ,
            appid VARCHAR(32)    COMMENT '应用编号' ,
            tid VARCHAR(32)    COMMENT '预警策略编号' ,
            stream_id VARCHAR(32)    COMMENT '流名称' ,
            channel_id VARCHAR(32)    COMMENT '频道' ,
            event_type VARCHAR(32)    COMMENT '事件类型' ,
            img VARCHAR(32)    COMMENT '预警图片链接' ,
            type VARCHAR(32)    COMMENT '图片类型' ,
            confidence INT    COMMENT '涉黄信度' ,
            normalScore INT    COMMENT '正常图片评分' ,
            hotScore INT    COMMENT '性感图片评分' ,
            pornScore INT    COMMENT '色情图片评分' ,
            level VARCHAR(32)    COMMENT '图片级别' ,
            ocrMsg VARCHAR(32)    COMMENT 'OCR识别信息' ,
            screenshotTime INT    COMMENT '截图时间' ,
            sendTime INT    COMMENT '请求时间' ,
            abductionRisk VARCHAR(1024)    COMMENT 'AbductionRisk' ,
            faceDetails VARCHAR(1024)    COMMENT '人脸属性' ,
            gameDetails VARCHAR(1024)    COMMENT '游戏详情' ,
            polityScore INT    COMMENT '涉政图片评分' ,
            illegalScore INT    COMMENT '违法图片评分' ,
            terrorScore INT    COMMENT '涉恐图片评分' ,
            similarScore INT    COMMENT '相识度评分' ,
            stream_param VARCHAR(32)    COMMENT '推流参数' ,
            app VARCHAR(32)    COMMENT '推流域名' ,
            appname VARCHAR(32)    COMMENT '推流路径' ,
            raw VARCHAR(3072)    COMMENT '原始日志' ,
            adddate INT    COMMENT '添加时间'
            * */

            //是否保存所有的鉴黄通知
            Boolean isSaveAllPornLog = true;
            if(!isSaveAllPornLog && "317".equals(params.get("event_type").toString())){
                return R.ok("鉴黄通知跳过归档,原因,该通知事件不是直播鉴黄事件");
            }

            LivePornLogEntity entity = new LivePornLogEntity();
            entity.setStreamId(params.get("streamId").toString());
            entity.setChannelId(params.get("channelId").toString());
            entity.setAppid(params.get("appid").toString());
            entity.setTid(params.get("appid").toString());
            entity.setEventType(params.get("event_type").toString());
            entity.setImg(params.get("img").toString());
            entity.setType(params.get("type").toString());

            entity.setConfidence(Integer.valueOf(params.get("confidence").toString()));
            entity.setNormalscore(Integer.valueOf(params.get("normalscore").toString()));
            entity.setHotscore(Integer.valueOf(params.get("hotscore").toString()));
            entity.setPornscore(Integer.valueOf(params.get("pornscore").toString()));

            entity.setLevel(params.get("level").toString());
            entity.setOcrmsg(params.get("ocrmsg").toString());
            entity.setScreenshottime(Integer.valueOf(params.get("screenshottime").toString()));
            entity.setSendtime(Integer.valueOf(params.get("sendtime").toString()));


            entity.setAbductionrisk(params.get("abductionrisk").toString());
            entity.setFacedetails(params.get("facedetails").toString());
            entity.setGamedetails(params.get("gamedetails").toString());

            entity.setPolityscore(Integer.valueOf(params.get("polityscore").toString()));
            entity.setIllegalscore(Integer.valueOf(params.get("illegalscore").toString()));
            entity.setTerrorscore(Integer.valueOf(params.get("terrorscore").toString()));
            entity.setSimilarscore(Integer.valueOf(params.get("similarscore").toString()));

            entity.setApp(params.get("app").toString());
            entity.setAppname(params.get("appname").toString());

            entity.setStreamParam(params.get("stream_param").toString());
            entity.setRaw(raw);
            entity.setAdddate(QuickHelper.getNowTimeStampSeconds());

            Integer uid = 0;

            try {
                uid = Integer.valueOf(entity.getStreamId());
            } catch (Exception e) {
                logger.info(String.format("uid = %s , convert error : %s", uid, e.getMessage()));
            }

            Boolean  result = livePornLogService.insert(entity);
            String msg = String.format("直播鉴黄 归档成功 : %s ", entity.getImg());
            if(result){
                logger.info(msg);
                return  R.ok(msg);
            }
            else{
                msg = "直播通知 鉴黄归档失败";
                logger.info(msg);
                return  R.ok(msg);
            }
        }

        return R.ok("通知完成").put("request.parameters",params);
    }

    @PostMapping("payment_otherpay_notify")
    @ApiOperation("other支付通知")
    public Object paymentOtherpayNotify(HttpServletRequest request) {
        logger.info(String.format("other支付通知回调开始"));

        String memberid = request.getParameter("memberid");
        String orderid = request.getParameter("orderid");
        String amount = request.getParameter("amount");
        String datetime = request.getParameter("datetime");
        String returncode = request.getParameter("returncode");
        String attach = request.getParameter("attach");
        String transactionId = request.getParameter("transaction_id");
        String sign = request.getParameter("sign");
        Map<String, Object> map = new HashMap<>();
        map.put("memberid",memberid);
        map.put("orderid",orderid);
        map.put("amount",amount);
        map.put("datetime",datetime);
        map.put("returncode",returncode);
        map.put("transaction_id",transactionId);

        logger.info(String.format("other支付通知回调参数：%s",QuickHelper.object2json(map)));

        if(StringUtils.isBlank(memberid)||StringUtils.isBlank(orderid)||
                StringUtils.isBlank(amount)||StringUtils.isBlank(datetime)||
                StringUtils.isBlank(returncode)||StringUtils.isBlank(transactionId)||
                StringUtils.isBlank(sign)){
            logger.info("参数为空");
            return "参数为空";
        }
        otherPayConfig.init("");
        String md5Sign=PayDigestUtil.getSign(map,otherPayConfig.getKey());

        if(sign.equalsIgnoreCase(md5Sign)){
            logger.info(String.format("验证通过：%s",sign));

            UserOrderEntity userOrderEntity=userOrderService.selectOne(new EntityWrapper().eq("id",orderid).eq("state",0));
            if(userOrderEntity==null){
                logger.info(String.format("订单: %s不存在或已完成通知",orderid));
                return "订单不存在或已完成通知";
            }
            String payOrderid=userOrderEntity.getId();
            Integer uid=userOrderEntity.getUid();
            if("00".equals(returncode)){
                //更新订单状态
                if(baseService.baseUpdateStatusSuccess(payOrderid,transactionId)){
                    //更新用户余额
                    switch (userOrderEntity.getObjectName()){
                        case "coin":
                            baseService.baseAddBalance(uid,userOrderEntity.getAmount(),userOrderEntity.getPlatform());
                            break;
                        case "gift":
                            baseService.baseAddGift(uid,Integer.valueOf(userOrderEntity.getObjectId()),userOrderEntity.getQuantity());
                            break;
                        case "vip":
                            baseService.baseUpdateVip(uid,userOrderEntity.getQuantity());
                            break;
                    }
                    //插入收支记录表
                    if(!baseService.baseAddUserPayment(userOrderEntity)){
                        logger.info(String.format("订单:%s 插入收支记录表失败",orderid));
                    }
                    logger.info(String.format("订单：%s 支付成功",orderid));
                }
            }else{
                baseService.baseUpdateStatusFail(payOrderid,transactionId);
                logger.info(String.format("订单：%s 支付失败",orderid));
            }
            return "OK";
        }
        logger.info(String.format("=================================验证不通过"));
        logger.info(String.format("=================================支付系统传参sign: %s",sign));
        logger.info(String.format("=================================系统验证md5key: %s",md5Sign));
        return "验证不通过";
    }

    @PostMapping("agora")
    @ApiOperation("agora实时语音通知")
    public Object paymentOtherpayNotify(@RequestBody Map<String,String> params) {
        logger.info("============= agora实时语音通知 =============");
        logger.info(QuickHelper.object2json(params));
        return R.ok();
    }
}
